//
// Created by QU on 24-6-27.
//

#ifndef JSON_PARSER_H
#define JSON_PARSER_H

#include <variant>
#include <unordered_map>
#include <vector>
#include <string>
#include <string_view>
#include <charconv>
#include <regex>

#include "../logger/logger.h"

namespace aquawius::json
{
    struct JsonObject;

    using JSONList = std::vector<JsonObject>;
    using JsonDict = std::unordered_map<std::string, JsonObject>;

    struct JsonObject
    {
        std::variant<
            std::monostate, // null
            bool, // true/false
            int, // 42
            double, // 114.514
            std::string, // "aquawius"
            JSONList, // [42, "aquawius"]
            JsonDict // { "hello": 985, "world" : 211 }
        > inner;

        JsonObject getValue(const std::string & strKey) const;
    };


    class JsonParser
    {
    public:
        /**
         * json解析器主函数
         * @param jsonString 需要解析的json字符串
         * @return 解析完成的数据结构
         */
        static JsonObject parseJson(std::string_view jsonString)
        {
            return innerParseMain(jsonString).first;
        }

        /**
         * 打印JsonObject的内容.
         * @param obj 需要打印的JsonObject数据结构
         * @param out 指定输出流
         * @param depth 默认缩进, 可以不写(无效值)
         */
        static void printJsonObject(const JsonObject& obj, std::ostream& out, int depth = 0);

    private:
        /**
         * 内部使用函数, 使用递归 + eaten的方式完成json解析
         * @param jsonString 需要解析的json字符串
         * @return pair.first是有用的解析完成的数据结构, pair.second供函数递归使用(无效值)
         */
         static std::pair<JsonObject, size_t> innerParseMain(std::string_view jsonString);

        /**
         * 内部使用函数, 将数字的字符串类型"11"/"42.42" 转换成 数字类型(int)11, (double)42.42, T为int或者double的一种.
         * @tparam T only int/double
         * @param str 一个数的字符串类型, "11"/"42.42"
         * @return std::optional<T> 如果有值, 为数字类型T(int/double), 也有可能没有值(std::nullopt)
         */
        template <typename T>
        static std::optional<T> try_parse_number(std::string_view str);

        /**
         * 内部使用函数, 为了完成类似 "\x0D" 这种转义单字符的解析使用的内部函数.
         * @param high 高字节 0
         * @param low 低字节 D
         * @return '0x0D'对应的char字符
         */
        static char hexToChar(char high, char low);

        /**
         * hexToChar(char high, char low) 的辅助函数
         */
        static int hexCharToInt(char ch);

        /**
         * 内部使用函数, 解析过程中, 需要完成两个版本的字符串解析, "stirng"和'string',
         * @param jsonString 需要解析的str
         * @param quote 只能是(')或者("), 用于区分两种解析版本
         * @return std::pair<std::string target, size_t eaten>.
         *  target是得出的结果, eaten是表示吃掉了多少字符.
         */
        static std::pair<std::string, size_t> innerParseString(const std::string_view& jsonString, char quote);

        /**
         * 内部使用函数, 输入一个指定的字符, 返回这个字符的转义版本 例如: 输入'n', 返回'\n'(换行符)
         * @param ch 输入
         * @return 输出对应的转义
         */
        static char unescaped_char(const char& ch);

        /**
         * 得到传入字符串的前面的空字符个数
         * @param jsonString 传入的string
         * @return 最前面空字符的个数
         */
        static size_t count_whitespace_begin(std::string_view jsonString);

    };
} // namespace aquawius::json

#endif // JSON_PARSER_H
